<template>
  <el-sub-menu :index="props.index">
    <template #title>PickStyle</template>
    <el-menu-item index="8-1" @click="createFeatureHighlighter">点击模型高亮</el-menu-item>
    <el-menu-item index="8-2" @click="mouseMoveHightLighted">移动模型高亮</el-menu-item>
    <el-menu-item index="8-3" @click="createNameOverlay">新建DIV并且显示</el-menu-item>
    <el-menu-item index="8-5" @click="highColor">高度范围着色</el-menu-item>
    <el-menu-item index="8-6" @click="materialColor">特定属性着色</el-menu-item>
    <el-menu-item index="8-7" @click="distanceColor">距离着色</el-menu-item>
    <el-menu-item index="8-8" @click="shaderColor">shader着色</el-menu-item>
  </el-sub-menu>
</template>

<script setup>
import * as Cesium from 'cesium'
import { useCesiumStore } from '@/stores/cesiumStore'
import { useTilesetStore } from '@/stores/tilesetStore'
import { ref, onMounted, onUnmounted } from 'vue'

// 定义props
const props = defineProps({
  index: {
    type: String,
    required: true,
  },
})

// 使用 Cesium Store
const cesiumStore = useCesiumStore()
// 使用 Tileset Store
const tilesetStore = useTilesetStore()
//点击模型高亮
const createFeatureHighlighter = () => {
  let currentFeature = undefined // 已高亮的要素
  let originalColor = undefined // Cesium.Color | undefined
  //// highlightColor 建议带不透明 alpha
  const highlightColor = Cesium.Color.AQUA.withAlpha(0.8)

  const handler = new Cesium.ScreenSpaceEventHandler(cesiumStore.viewerCesium.canvas)

  handler.setInputAction((click) => {
    //position: Cartesian2 {x: 1098.9090576171875, y: 545.8181762695312}
    // console.log('点击了click', click)
    const position = click.position
    /* ① 还原旧要素 —— 只有 originalColor 真的是 Cesium.Color 时才还原 */
    if (currentFeature && originalColor instanceof Cesium.Color) {
      currentFeature.color = originalColor
    }

    /* ② 拾取新要素 */
    const picked = cesiumStore.viewerCesium.scene.pick(position)
    //未拾取dao
    if (!Cesium.defined(picked)) {
      currentFeature = undefined
      originalColor = undefined
      return
    }

    /* ③ 保存原色：若原本没有颜色，则记 undefined，表示无需还原 */
    originalColor =
      picked.color instanceof Cesium.Color
        ? Cesium.Color.clone(picked.color, new Cesium.Color()) //返回Cesium.Color对象 存储的picked.color
        : undefined

    /* ④ 设高亮色（clone 可避免篡改常量）*/
    picked.color = Cesium.Color.clone(highlightColor, new Cesium.Color())
    currentFeature = picked //当前点击的
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

  handler.setInputAction(() => {
    //用 removeInputAction 而不要 destroy()
    //每个 handler 互不影响。 调用 handlerA.destroy() 只会移除 handlerA 上的回调，handlerB 的事件仍然有效。
    //handler.destroy() 会把 这个 ScreenSpaceEventHandler 实例上注册的 所有 事件回调一次性注销并释放资源
    handler.destroy()
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}

//移动模型高亮
const mouseMoveHightLighted = () => {
  // cesiumStore.viewerCesium.screenSpaceEventHandler.setInputAction(
  //   {},
  //   Cesium.ScreenSpaceEventType.MOUSE_MOVE,
  // )
  let current = undefined // 已高亮 feature
  let original = undefined // Cesium.Color 或 undefined
  const highlight = Cesium.Color.AQUA.withAlpha(0.8)

  // 独立 handler，方便启停
  const handler = new Cesium.ScreenSpaceEventHandler(cesiumStore.viewerCesium.canvas)

  handler.setInputAction((movement) => {
    //endPosition: Cartesian2 {x: 405.0909118652344, y: 1044.7274169921875}
    //startPosition: Cartesian2 {x: 405.0909118652344, y: 1043.272705078125}
    // console.log('鼠标移动movement', movement)
    const windowPos = movement?.endPosition
    if (!windowPos) return
    // // ① 拾取
    const picked = cesiumStore.viewerCesium.scene.pick(windowPos)
    // const picked = cesiumStore.viewerCesium.scene.pick(position)
    if (!Cesium.defined(picked)) {
      // 没捡到任何东西 → 还原旧的 & 退出
      if (current && original instanceof Cesium.Color) current.color = original
      current = undefined
      original = undefined
      return
    }
    //打印信息
    console.log('字段', picked.getPropertyIds()) //模型的属性字段
    console.log('Name', picked.getProperty('name')) //模型的属性 值

    // ② 若跟上一次是同一个 feature，就不必重复改色（节流）
    if (current === picked) return

    // ③ 先还原旧要素
    if (current && original instanceof Cesium.Color) {
      current.color = original
    }

    // ④ 保存新要素原色（可能 undefined）
    original =
      picked.color instanceof Cesium.Color
        ? Cesium.Color.clone(picked.color) // 第二参可省略
        : undefined

    // ⑤ 设置高亮
    picked.color = Cesium.Color.clone(highlight)
    current = picked
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

  handler.setInputAction(() => {
    //用 removeInputAction 而不要 destroy()
    //每个 handler 互不影响。 调用 handlerA.destroy() 只会移除 handlerA 上的回调，handlerB 的事件仍然有效。
    //handler.destroy() 会把 这个 ScreenSpaceEventHandler 实例上注册的 所有 事件回调一次性注销并释放资源
    handler.destroy()
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
//创建盒子   点击显示名称
const createNameOverlay = () => {
  const overlayEl = ref(null)
  // 已经存在 → 直接显示
  if (overlayEl.value) {
    overlayEl.value.style.display = 'block'
    return
  }

  if (!cesiumStore.viewerCesium) return

  /* 真正创建 DOM */
  const overlay = document.createElement('div')
  overlay.className = 'backdrop'
  //Object.assign() 是一个 JavaScript 方法，用于将一个或多个源对象的所有可枚举属性复制到目标对象
  Object.assign(overlay.style, {
    position: 'absolute',
    left: '0',
    bottom: '0',
    padding: '10px',
    backgroundColor: 'white',
    borderRadius: '4px',
    boxShadow: '0 1px 4px rgba(0,0,0,.25)',
    pointerEvents: 'none',
    fontSize: '14px',
    display: 'none',
  })
  overlay.textContent = 'Hello overlay!'
  cesiumStore.viewerCesium.container.appendChild(overlay)
  overlayEl.value = overlay

  // 独立 handler，方便启停
  const handler = new Cesium.ScreenSpaceEventHandler(cesiumStore.viewerCesium.canvas)

  handler.setInputAction((click) => {
    //endPosition: Cartesian2 {x: 405.0909118652344, y: 1044.7274169921875}
    //startPosition: Cartesian2 {x: 405.0909118652344, y: 1043.272705078125}
    // console.log('鼠标移动movement', movement)
    const position = click.position
    // // ① 拾取
    const picked = cesiumStore.viewerCesium.scene.pick(position)
    // const picked = cesiumStore.viewerCesium.scene.pick(position)
    if (!Cesium.defined(picked)) {
      // 没捡到任何东西 → 退出
      overlay.style.display = 'none'
      return
    }
    overlay.style.display = 'block'
    //cesiumStore.viewerCesium.canvas.clientHeight  画布的总高度
    overlay.style.bottom = `${cesiumStore.viewerCesium.canvas.clientHeight - position.y}px`
    overlay.style.left = `${position.x}px`
    let name = picked.getProperty('name')
    if (!Cesium.defined(name)) {
      name = '未知命名'
    }
    overlay.textContent = name
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

  handler.setInputAction(() => {
    //用 removeInputAction 而不要 destroy()
    //每个 handler 互不影响。 调用 handlerA.destroy() 只会移除 handlerA 上的回调，handlerB 的事件仍然有效。
    //handler.destroy() 会把 这个 ScreenSpaceEventHandler 实例上注册的 所有 事件回调一次性注销并释放资源
    handler.destroy()
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
//高度着色
const highColor = () => {
  console.log('高亮')
  if (!tilesetStore.whiteModel) return
  // 创建一个高亮样式
  tilesetStore.whiteModel.style = new Cesium.Cesium3DTileStyle({
    color: {
      conditions: [
        ['Number(${Height}) >= 100', 'color("purple")'],
        ['Number(${Height}) >= 50', 'color("orange")'],
        ['Number(${Height}) >= 25', 'color("yellow")'],
        ['Number(${Height}) >= 10', 'color("green")'],
      ],
    },
    show: 'Number(${Height})> 0',
  })
}
//属性着色
const materialColor = () => {
  if (!tilesetStore.osmBuildings) return
  // 创建一个高亮样式
  tilesetStore.osmBuildings.style = new Cesium.Cesium3DTileStyle({
    // 作用：defines 用于创建可在样式表达式中重复使用的变量。
    // 具体解释：
    // 这里定义了一个名为 material 的变量
    // feature 是一个包含当前要素所有属性的对象 feature['building:material'] 访问建筑材料属性
    // ${feature['building:material']} 是一个表达式，用于获取每个建筑物特征（feature）的
    defines: {
      material: "${feature['building:material']}",
    },
    color: {
      conditions: [
        ['${material} === null', "color('white')"],
        ["${material} === 'glass'", "color('skyblue', 0.5)"],
        ["${material} === 'concrete'", "color('grey')"],
        ["${material} === 'brick'", "color('indianred')"],
        ["${material} === 'stone'", "color('lightslategrey')"],
        ["${material} === 'metal'", "color('lightgrey')"],
        ["${material} === 'steel'", "color('lightsteelblue')"],
        ['true', "color('white')"], // This is the else case
      ],
    },
  })
}
//距离着色
const distanceColor = () => {
  if (!tilesetStore.osmBuildings) return

  // 独立 handler，方便启停
  const handler = new Cesium.ScreenSpaceEventHandler(cesiumStore.viewerCesium.canvas)
  handler.setInputAction((click) => {
    const position = click.position
    // // ① 拾取
    const picked = cesiumStore.viewerCesium.scene.pick(position)
    // const picked = cesiumStore.viewerCesium.scene.pick(position)
    if (!Cesium.defined(picked)) {
      // 没捡到任何东西 → 退出
      return
    }
    //鼠标点击的位置坐标
    const pickedLongitude = picked.getProperty('cesium#longitude')
    const pickedLatitude = picked.getProperty('cesium#latitude')
    tilesetStore.osmBuildings.style = new Cesium.Cesium3DTileStyle({
      defines: {
        //feature 是 Cesium 中表示地理要素的对象（如点、线、面等）
        //${feature['cesium#longitude']} - 获取当前要素的经度值  ${feature['cesium#latitude']} - 获取当前要素的纬度值
        //vec2 是一个表示二维向量的数据类型
        //distance 函数计算两个向量之间的距离，这里使用了 vec2 类型的向量作为参数，并返回一个浮点数（距离）
        //         这个距离值表示两点在经纬度坐标系中的直线距离。例如：
        // 如果结果是 0，表示两点完全重合
        // 如果结果是 0.01，表示两点相距约 0.01 度
        // 如果结果是 1，表示两点相距 1 度（在赤道附近大约等于 111 公里）
        distance: `distance(vec2(\${feature['cesium#longitude']}, \${feature['cesium#latitude']}), vec2(${pickedLongitude},${pickedLatitude}))`,
      },
      color: {
        conditions: [
          ['${distance} > 0.014', "color('blue')"],
          ['${distance} > 0.010', "color('green')"],
          ['${distance} > 0.006', "color('yellow')"],
          ['${distance} > 0.0001', "color('red')"],
          ['true', "color('white')"], //默认条件 兜底条件
        ],
      },
    })
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
//shader
const shaderColor = () => {
  if (!tilesetStore.osmBuildings) return
  //CustomShader 自定义着色器
  tilesetStore.osmBuildings.customShader = new Cesium.CustomShader({
    //Cesium.LightingModel.UNLIT：不计算任何光照效果  模型将直接使用材质的颜色，不考虑光源、阴影等
    //Cesium.LightingModel.PBR：基于物理的渲染 (Physically Based Rendering)  提供最真实的光照效果，考虑材质的金属度、粗糙度等物理属性
    // Cesium.LightingModel.GLTF：使用 glTF 标准中定义的光照模型
    lightingModel: Cesium.LightingModel.UNLIT,
    //模型坐标系(MC - Model Coordinates)   模型的本地坐标系   原点和方向取决于模型的创建方式  在着色器中通过positionMC、normalMC等访问
    // 世界坐标系(WC - World Coordinates)  地球固定坐标系(ECEF)  原点在地球中心    在着色器中通过positionWC访问
    // 眼坐标系(EC - Eye Coordinates)  以相机/观察者为中心的坐标系  原点在相机位置  Z轴指向观察方向 在着色器中通过positionEC、normalEC等访问
    //窗口坐标系(WC - Window Coordinates) 2D屏幕空间坐标  原点通常在屏幕左下角  单位为像素
    //fragmentShaderText 自定义片段着色器作为 GLSL 代码字符串。它必须包含一个名为 fragmentMain 的 GLSL 函数
    //FragmentInput fsInput: 包含位置、法线等输入属性
    //inout czm_modelMaterial material: 可以修改的材质属性
    //fsInput.attributes 是 Cesium 自定义着色器（CustomShader）中的一个对象，它提供了访问片段着色器（fragment shader）输入属性的方式
    fragmentShaderText: `
                  void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
                      // 可以修改的参数
                      // 注意shader中写浮点数是，一定要带小数点，否则会报错，比如0需要写成0.0，1要写成1.0
                      float _baseHeight = 0.0; // 物体的基础高度，需要修改成一个合适的建筑基础高度
                       float _heightRange = 15.0; // 高亮的范围(_baseHeight ~ _baseHeight + _heightRange) 默认是 0-60米
                       float _glowRange = 300.0; // 光环的移动范围(高度)

                       // 建筑基础色
                       float vtxf_height = fsInput.attributes.positionMC.y - _baseHeight;
                       float vtxf_a11 = fract(czm_frameNumber / 120.0) * 3.14159265 * 2.0;
                       float vtxf_a12 = vtxf_height / _heightRange + sin(vtxf_a11) * 0.1;
                       material.diffuse *= vec3(vtxf_a12, vtxf_a12, vtxf_a12);
                       material.diffuse *= vec3(0, .5, 1.);

                       // 动态光环
                       float vtxf_a13 = fract(czm_frameNumber / 360.0);
                       float vtxf_h = clamp(vtxf_height / _glowRange, 0.0, 1.0);
                       vtxf_a13 = abs(vtxf_a13 - 0.5) * 2.0;
                       float vtxf_diff = step(0.005, abs(vtxf_h - vtxf_a13));
                       material.diffuse += material.diffuse * (1.0 - vtxf_diff);

                       //material.diffuse = vec3(0.0, 0.0, 1.0);
                       //material.diffuse.g = -fsInput.attributes.positionEC.z / 1.0e4;
             }


`, // //#region
    // `
    //   void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
    //     // 示例1: 基础颜色 - 将所有建筑设为蓝色
    //     material.diffuse = vec3(0.0, 0.3, 0.8);

    //     // 示例2: 基于高度的渐变色
    //     // vec3 positionEC = fsInput.attributes.positionEC; // 使用眼坐标系
    //     // float height = length(positionEC); // 简化的高度计算
    //     // float normalizedHeight = clamp(height / 1000.0, 0.0, 1.0);
    //     // material.diffuse = mix(vec3(0.0, 0.2, 0.8), vec3(1.0, 0.2, 0.1), normalizedHeight);

    //     // 示例3: 建筑轮廓高亮 (使用normalEC代替normalMC)
    //     // vec3 normal = fsInput.attributes.normalEC; // 使用眼坐标系中的法线
    //     // vec3 viewDir = normalize(-fsInput.attributes.positionEC); // 在眼坐标系中，视线方向就是指向原点
    //     // float fresnel = 1.0 - max(0.0, dot(normal, viewDir));
    //     // if (fresnel > 0.7) {
    //     //   material.diffuse = vec3(1.0, 1.0, 0.0); // 黄色边缘
    //     // } else {
    //     //   material.diffuse = vec3(0.2, 0.2, 0.8); // 蓝色主体
    //     // }

    //     // 示例4: 随时间变化的颜色
    //     // float time = czm_frameNumber / 60.0;
    //     // float pulse = 0.5 + 0.5 * sin(time);
    //     // material.diffuse = mix(vec3(0.0, 0.2, 0.8), vec3(0.8, 0.2, 0.0), pulse);

    //     // 示例5: 基于位置的纹理 (使用positionEC代替positionMC)
    //     // vec3 position = fsInput.attributes.positionEC;
    //     // float checkSize = 50.0;
    //     // float i = floor(position.x / checkSize);
    //     // float j = floor(position.z / checkSize);
    //     // float modResult = mod(i + j, 2.0);
    //     // if (modResult < 0.5) {
    //     //   material.diffuse = vec3(0.3, 0.3, 0.8);
    //     // } else {
    //     //   material.diffuse = vec3(0.8, 0.3, 0.3);
    //     // }
    //   }
    // `,
    //#endregion
  })
}
</script>

<style lang="scss" scoped></style>
